#include "water_module.h"
#include "log_module.h"
#include "alarm_module.h"
#include <rtdevice.h>

static water_config_t *water_config = RT_NULL;
static rt_thread_t water_thread = RT_NULL;
static rt_adc_device_t water_adc_dev = RT_NULL;

/* Filter buffers for water quality data */
static struct {
    uint8_t index;
    uint8_t count;
    float buffer[10];
    float sum;
} water_filters[WATER_CHANNELS];

static float adc_raw_to_resistance(uint16_t raw_value, uint8_t channel)
{
    /* Assuming voltage divider circuit:
     * Vout = Vin * R_unknown / (R_known + R_unknown)
     * R_unknown = R_known * Vout / (Vin - Vout)
     */
    float vcc = 3.3f;  /* Supply voltage */
    float r_known = 10000.0f;  /* 10K reference resistor */
    
    /* Convert ADC raw value to voltage */
    float vout = (raw_value / 4095.0f) * vcc;
    
    /* Calculate unknown resistance */
    if (vout >= vcc - 0.001f) {
        return 1000000.0f;  /* Very high resistance (open circuit) */
    }
    
    if (vout <= 0.001f) {
        return 0.0f;  /* Very low resistance (short circuit) */
    }
    
    float resistance = r_known * vout / (vcc - vout);
    return resistance;
}

static float resistance_to_quality(uint8_t channel, float resistance)
{
    float quality_value;
    
    /* Simple linear conversion from resistance to quality value */
    quality_value = linear_calibration(resistance, 
                                      water_config->channels[channel].k_factor,
                                      water_config->channels[channel].b_offset);
    
    /* Apply table calibration if available */
    if (water_config->channels[channel].cal_table_size > 0) {
        quality_value = table_calibration(resistance,
                                        water_config->channels[channel].cal_table,
                                        water_config->channels[channel].cal_table_size);
    }
    
    return quality_value;
}

static float moving_average_filter(uint8_t channel, float new_value)
{
    if (water_filters[channel].count < 10) {
        water_filters[channel].buffer[water_filters[channel].count] = new_value;
        water_filters[channel].sum += new_value;
        water_filters[channel].count++;
        return new_value;
    }
    
    /* Subtract oldest value */
    water_filters[channel].sum -= water_filters[channel].buffer[water_filters[channel].index];
    
    /* Add new value */
    water_filters[channel].buffer[water_filters[channel].index] = new_value;
    water_filters[channel].sum += new_value;
    
    /* Update index */
    water_filters[channel].index = (water_filters[channel].index + 1) % 10;
    
    return water_filters[channel].sum / 10.0f;
}

static rt_err_t water_adc_init(void)
{
    /* Find ADC device - use same ADC as 4-20mA module */
    water_adc_dev = (rt_adc_device_t)rt_device_find("adc1");
    if (water_adc_dev == RT_NULL) {
        LOG_E("Water quality ADC device not found\n");
        return RT_ERR_NOT_FOUND;
    }
    
    /* Enable ADC channels for water quality */
    rt_adc_enable(water_adc_dev, WATER_ADC_CH1);
    rt_adc_enable(water_adc_dev, WATER_ADC_CH2);
    
    return RT_OK;
}

static void process_water_message(message_t *msg)
{
    if (msg == RT_NULL) return;
    
    switch (msg->msg_type) {
        case MSG_CONTROL_CMD:
            /* Handle water quality control commands */
            break;
        default:
            break;
    }
}

rt_err_t water_module_init(void)
{
    rt_err_t result;
    
    /* Get configuration pointer */
    water_config = &g_system_config.water;
    
    /* Initialize ADC */
    result = water_adc_init();
    if (result != RT_OK) {
        LOG_E("Water quality ADC initialization failed\n");
        return result;
    }
    
    /* Initialize filters */
    for (int i = 0; i < WATER_CHANNELS; i++) {
        water_filters[i].index = 0;
        water_filters[i].count = 0;
        water_filters[i].sum = 0.0f;
        rt_memset(water_filters[i].buffer, 0, sizeof(water_filters[i].buffer));
    }
    
    /* Create water quality thread */
    water_thread = rt_thread_create("water", 
                                   water_thread_entry, 
                                   RT_NULL, 
                                   1024, 
                                   14, 
                                   20);
    if (water_thread == RT_NULL) {
        LOG_E("Failed to create water quality thread\n");
        return RT_ERR_MEM;
    }
    
    LOG_I("Water quality module initialized successfully\n");
    return RT_OK;
}

void water_thread_entry(void *parameter)
{
    rt_uint32_t tick;
    uint16_t raw_value;
    float resistance, quality_value, filtered_quality;
    
    while (1) {
        tick = rt_tick_get();
        
        /* Read all water quality channels */
        for (int i = 0; i < WATER_CHANNELS; i++) {
            if (!water_config->channels[i].enabled) {
                continue;
            }
            
            /* Read raw ADC value */
            if (i == 0) {
                raw_value = rt_adc_read(water_adc_dev, WATER_ADC_CH1);
            } else {
                raw_value = rt_adc_read(water_adc_dev, WATER_ADC_CH2);
            }
            
            /* Convert to resistance */
            resistance = adc_raw_to_resistance(raw_value, i);
            
            /* Convert to quality value */
            quality_value = resistance_to_quality(i, resistance);
            
            /* Apply filter */
            filtered_quality = moving_average_filter(i, quality_value);
            
            /* Update configuration */
            water_config->channels[i].resistance = resistance;
            water_config->channels[i].quality_value = filtered_quality;
        }
        
        /* Send data ready message */
        send_message(MODULE_ALARM, MSG_DATA_UPDATE, RT_NULL, 0);
        send_message(MODULE_MODBUS, MSG_DATA_UPDATE, RT_NULL, 0);
        
        /* Wait for next cycle */
        rt_thread_delay_until(&tick, rt_tick_from_millisecond(water_config->base.update_interval));
    }
}

float water_get_resistance(uint8_t channel)
{
    if (channel >= WATER_CHANNELS || water_config == RT_NULL) {
        return 0.0f;
    }
    
    return water_config->channels[channel].resistance;
}

float water_get_quality_value(uint8_t channel)
{
    if (channel >= WATER_CHANNELS || water_config == RT_NULL) {
        return 0.0f;
    }
    
    return water_config->channels[channel].quality_value;
}

rt_err_t water_set_calibration(uint8_t channel, float k, float b)
{
    if (channel >= WATER_CHANNELS || water_config == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    water_config->channels[channel].k_factor = k;
    water_config->channels[channel].b_offset = b;
    
    LOG_I("Water quality channel %d calibration updated: k=%.3f, b=%.3f\n", 
          channel, k, b);
    
    return RT_OK;
}

rt_err_t water_set_cal_table(uint8_t channel, cal_point_t *table, uint8_t size)
{
    if (channel >= WATER_CHANNELS || water_config == RT_NULL || table == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    if (size > 4) size = 4;
    
    rt_memcpy(water_config->channels[channel].cal_table, table, size * sizeof(cal_point_t));
    water_config->channels[channel].cal_table_size = size;
    
    LOG_I("Water quality channel %d calibration table updated, size=%d\n", channel, size);
    
    return RT_OK;
}

water_config_t *water_get_config(void)
{
    return water_config;
}